from .taskrunner import TaskRunner
from exceptions import *
import ma.const
import ma.log
import os
import time

class MapTaskRunner(TaskRunner):
    # TODO: Remove the threads argument ... no use
    def __init__(self, tip_info, user_module_name, user_class_name):
        """Map Task Runner constructs Task Runner, and the main output 
        dictionary
        """
        TaskRunner.__init__(self, tip_info, user_module_name, user_class_name)
        
        #this is the dict to which the user function will emit its key, value tuples
        #the struct is key -> list_of_values
        #this is the key value dict that will persist for the life of this mapTIP as
        #files are read one by one by the map and the key value pairs emitted will be
        #appended to it and then finally written to a file
        self.key_value_dict = {}
        
        self.__log = ma.log.get_logger("ma.codes")

        
    def startTask(self):
        """This func is called to start the user defined code as a separate 
        process
        """   
            
        #must be in a try except block!
        #look up the map function to be called from the job_xml
        #initiate a separate process using the user func as the program to run
        #return the pid of the new process to the MapTIP so that it can 
        #interact with it????????????????
                
        self.__log.info('Actual processing on map %s STARTED in a separate PROCESS', self.tip_info.returnTaskID())
        
        self.input_dest_dir = ma.const.JobsXmlData.get_filepath_str_data(ma.const.xml_local_input_temp_dir, self.tip_info.job_id) + os.sep
        
        for i in self.tip_info.input_data:
            filename = str(i[0])
            filepath = self.input_dest_dir + filename 

            try:
                self.__log.info('Input file to map %s: %s', self.tip_info.returnTaskID(), filepath)
                
                f = open(filepath, 'r')
                filecontents = f.read()
                f.close()
                
                self.__log.info('Input file to map %s read completely: %s', self.tip_info.returnTaskID(), filepath)
                
                # TODO: Need to do all of this on process
                th = eval( 'self.user_class.' + self.user_class_name + '(filename, filecontents, self.key_value_dict)' )
                self.threads.append(th)
                th.start()
                th.join()
                
            except IOError as err_msg:
                self.__log.error("Error while reading map input or running task: %s", err_msg)
                os._exit(-1)
        
        self.__log.info('Actual processing on map %s ENDED', self.tip_info.returnTaskID())
        
        print("--> MAPPED", len(self.key_value_dict), "Keys") 
        
        # write the dictionary to the output file
        if not self.writeOutputToLocalFile():
            # some error occurred
            os._exit(-1)
        else:
            # ran fine
            os._exit(0)
    
            
    def writeOutputToLocalFile(self):
        """This function writes the output to the output file specified by the
        XML. The output would be in the form of a dictionary
        """
        
        raise NotImplementedError('This function is defined by each individual implementation')
    
    
    @staticmethod
    def write_keylines(fd, dict):
        """This function writes each key in the dictionary to a separate line
        """
        
        for key in dict:
            # write the key
            fd.write(key)
            
            # write the colon
            fd.write(':')
            
            # write the values and remove the list brackets
            fd.write(str(dict[key])[1:-1])
            
            fd.write('\n')
            